﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace BPMS.Core
{
    public class DataStructureCache
    {
        private readonly static ConcurrentDictionary<RuntimeTypeHandle, string> tableInfoCache = new ConcurrentDictionary<RuntimeTypeHandle, string>();
        private readonly static ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<DataFieldAttribute>> fieldInfoCache = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<DataFieldAttribute>>();
        private readonly static ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> propertyCache = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
        private readonly static ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> keyPropertyCache = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
        public static string GetDataRecordName(Type type)
        {
            string recordName = string.Empty;
            if (tableInfoCache.TryGetValue(type.TypeHandle, out recordName))
            {
                return recordName;
            }
            DataRecordAttribute recordAttribute = type.GetCustomAttributes(typeof(DataRecordAttribute), false).FirstOrDefault() as DataRecordAttribute;
            if (null != recordAttribute)
            {
                recordName = string.Format("[{0}].[{1}].[{2}]", recordAttribute.DataBase, recordAttribute.Schema, recordAttribute.Name);
            }
            tableInfoCache[type.TypeHandle] = recordName;
            return recordName;
        }

        public static IEnumerable<PropertyInfo> GetPropertyList(Type type)
        {
            IEnumerable<PropertyInfo> resultProperty = null;
            if (propertyCache.TryGetValue(type.TypeHandle, out resultProperty))
            {
                return resultProperty;
            }
            resultProperty = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            propertyCache[type.TypeHandle] = resultProperty;
            return resultProperty;
        }

        public static IEnumerable<DataFieldAttribute> GetDataFieldList(Type type)
        {
            IEnumerable<DataFieldAttribute> resultField = new List<DataFieldAttribute>();
            if (fieldInfoCache.TryGetValue(type.TypeHandle, out resultField))
            {
                return resultField;
            }
            IEnumerable<PropertyInfo> propertyList = GetPropertyList(type);
            resultField = propertyList.Select(item => item.GetCustomAttributes(typeof(DataFieldAttribute), false).FirstOrDefault() as DataFieldAttribute);
            fieldInfoCache[type.TypeHandle] = resultField;
            return resultField;
        }

        public static IEnumerable<PropertyInfo> GetKeyPropertyList(Type type)
        {
            IEnumerable<PropertyInfo> resultProperty = null;
            if (keyPropertyCache.TryGetValue(type.TypeHandle, out resultProperty))
            {
                return resultProperty;
            }
            IEnumerable<PropertyInfo> allProperties = GetPropertyList(type);
            IEnumerable<PropertyInfo> keyProperties = allProperties.Where(item =>
            {
                DataFieldAttribute fieldAttribute = (item.GetCustomAttributes(typeof(DataFieldAttribute), false).FirstOrDefault() as DataFieldAttribute);
                if (null == fieldAttribute)
                    return false;
                return fieldAttribute.IsPrimaryKey;
            });
            keyPropertyCache[type.TypeHandle] = keyProperties;
            return null;
        }
    }
}
